package com.apestech.framework.xml.sql;

import java.util.ArrayList;
import java.util.List;
import com.apestech.framework.db.SqlSession;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.sql.SqlUtil;
import com.apestech.framework.sql.condition.ConditionMap;
import com.apestech.framework.sql.modul.FromList;
import com.apestech.framework.xml.plugin.modul.FromField;
import com.apestech.framework.xml.plugin.modul.GridHead;
import com.apestech.framework.xml.sql.modul.QueryRule;
import com.apestech.framework.xml.sql.modul.QueryhTw;
import com.apestech.framework.xml.sql.modul.SqlRule;
import com.apestech.framework.xml.sql.node.NodeExpress;
import com.apestech.framework.xml.sql.node.NodeRule;
import org.dom4j.Attribute;
import org.dom4j.CDATA;
import org.dom4j.Element;
import org.dom4j.Text;
import com.apestech.framework.sql.modul.SqlList;
import com.apestech.framework.sql.modul.VarList;
import com.apestech.framework.xml.pub.core.XmlFile;

/**
 * 根据mybatis解析思路，重构SQL解析XML部分的逻辑，注意变量$声明是解析为值，#声明解析为?
 * @author hupo
 *
 */
public class XmlSqlPaste extends SqlUtil {

	private String xmlSql=null;
	private String sql="";
	private SqlList param;
	private SqlNodeVar.SqlType type=SqlNodeVar.SqlType.SQL;
	private Element root;
	private Element node;
	private String autoCompletion;
	private String from;
	private FromList fromtab;
	private JSONObject froms;
	private String DBCN;
	private SqlSession session;
	private QueryRule rule;
	private JSONArray auths;
	private QueryhTw htw;
	private GridHead head;
	private XmlSqlPaste xmlSqlPaste;
	private SqlRule sqlrule;
	private String sqlType;
	private JSONObject other;
	
	public XmlSqlPaste(String sql, SqlNodeVar.SqlType type, SqlSession session){
		this.xmlSql=sql;
		this.type=type;
		this.session=session;
		if(type==SqlNodeVar.SqlType.XML_SQL){
			this.xmlSql=iniSql(this.xmlSql);
		}
	}

	public XmlSqlPaste(Element root, Element node, SqlSession session){
		this.session=session;
		this.node=node;
		this.root=root;
		this.type=SqlNodeVar.SqlType.XML;
	}

	public SqlList getParam(){
		return this.param;
	}

	public SqlNodeVar.SqlType getType() {
		return type;
	}

	public String getSql(){
		return this.sql;
	}

	public void setFromtab(String from) throws Exception {
		if(this.session==null){
			throw new Exception("请先设置session！");
		}
		this.from=from;
		if(from!=null){
			fromtab=new FromList(from, null, session);
		}
	}

	public QueryRule getRule(){
		return rule;
	}

	private Element getElementFromString() throws Exception {
		XmlFile file=new XmlFile();
		file.loadFromString(this.xmlSql);
		Element root=file.getRoot();
		return root;
	}
	
	public String getSql(ConditionMap input) throws Exception{
		sql="";
		param=new SqlList();
		if(type==SqlNodeVar.SqlType.SQL && xmlSql.indexOf("/>")<0 && xmlSql.indexOf("</")<0){
			return getSqlFromInSql(input);
		} else {
			if(xmlSql!=null){
				type=SqlNodeVar.SqlType.XML_SQL;
			}
			return getSqlFromXml(input);
		}
	}

	private String getSqlFromInSql(ConditionMap input) throws Exception {
		String s=xmlSql;
		if(fromtab==null && s!=null && node!=null){
			fromtab=new FromList(null, s, session);
		}
		if(s==null){
			throw new Exception("当前传入SQL为空，请检查代码逻辑！");
		}
		if(s.indexOf(SqlNodeVar.getWhereStr())>0){
			String[] wlist=s.split(SqlNodeVar.getWhereStr());
			int wlen=wlist.length;
			for(int w=0; w<wlen; w++){
				sql=addSql(fromtab, wlist[w], input, param, sql);
				if(w!=(wlen-1)){
					sql=addSql(fromtab, SqlNodeVar.getWhereStr().trim(), input, param, sql);
				}
			}
		} else {
			sql=addSql(fromtab, s, input, param, sql);
		}
		return sql;
	}

	private String getSqlFromXml(ConditionMap input) throws Exception {
		if(type==SqlNodeVar.SqlType.XML_SQL){
			node=getElementFromString();
		} else {
			fromtab=null;
		}
		if(this.node==null && root!=null) this.node=root;
		if(this.node==null) return null;
		List<Attribute> alist = node.attributes();
		for (Attribute attr : alist) {
			String key=attr.getName().trim();
			String keyl=key.toLowerCase();
			String value=attr.getValue().trim();
			if("from".indexOf(keyl)>=0){
				if(keyl.length()==4){
					from=value;
					fromtab=new FromList(from, null, session);
				} else {
					if(froms==null){
						froms=new JSONObject();
					}
					froms.put(keyl, new FromField(value, new FromList(value, null, session)));
				}
			} else if("autocompletion".equals(keyl)){
				autoCompletion=value;
			} else if("DBCN".equals(key.toUpperCase())){
				DBCN=value;
			} else {
				if(other==null) other=new JSONObject();
				other.put(key, value);
			}
		}

		List<?> list=node.content();
		int len=list.size();
		for(int i=0;i<len;i++){
			String scalss=list.get(i).getClass().getName();
			if("org.dom4j.tree.DefaultText".equals(scalss) || "org.dom4j.tree.DefaultCDATA".equals(scalss)){
				String s="";
				if("org.dom4j.tree.DefaultText".equals(scalss)){
					s=((Text) list.get(i)).getText().trim();
				} else {
					s=((CDATA) list.get(i)).getText().trim();
				}
				SqlComment comm=new SqlComment(s);
				s=comm.getSql();
				setSqlWhere(s, input);
			} else if(scalss.equals("org.dom4j.tree.DefaultElement")){
				Element eml=(Element) list.get(i);
				NodeExpress ex=new NodeExpress(root, eml, input, session);
				ex.setFromtab(fromtab);
				ex.doExpress();
				sql=sql+" "+ex.getText()+" ";
				setSqlWhere(ex.getText(), input);
				//param.add(ex.getParam());
				if(rule==null){
					rule=ex.getRule();
				}
				if(htw==null){
					htw=ex.getHtw();
				}
				if(head==null){
					head=ex.getHead();
				}
				if(xmlSqlPaste==null){
					xmlSqlPaste=ex.getXmlSqlPaste();
				}
				if(ex.getAuths()!=null){
					if(auths==null){
						auths=ex.getAuths();
					} else auths.addAll(ex.getAuths());
				}
				if(sqlrule==null){
					sqlrule=ex.getSqlrule();
				}

				if(ex.getOther()!=null){
					if(other==null) other=ex.getOther();
					else other.putAll(ex.getOther());
				}
			}
		}

		if(rule==null && fromtab!=null){
			NodeRule nrule=new NodeRule(fromtab.getFrom());
			rule=nrule.getRule();
		}
		if(rule!=null){
			if(rule.getFrom()==null && fromtab!=null){
				rule.setFrom(fromtab.getFrom());
			}
			if(rule.getFroms()==null){
				rule.setFroms(froms);
			} else {
				froms=rule.getFroms();
				ArrayList<String> klist=froms.getKeylist();
				int klen=klist.size();
				for(int k=0; k<klen; k++){
					String key=klist.get(k);
					FromField f= (FromField) froms.get(key);
					f.setFromtab(new FromList(f.getFrom(), null, session));
					froms.put(key, f);
				}
			}
		}

		xmlSql=sql;
		if(sql.indexOf("</if")>=0 || sql.indexOf("</IF")>=0){
			sql="";
			param=new SqlList();
			type=SqlNodeVar.SqlType.XML_SQL;
			xmlSql=iniSql(xmlSql);
			sql=getSqlFromXml(input);
			xmlSql=finiSql(sql);
			sql=xmlSql;
		}
		return sql;
	}

	private void setSqlWhere(String s, ConditionMap input) throws Exception {
		if(!("").equals(s)){
			if(!leftStr(s,1).equals("'") && countString(s,"'") / 2==0){
				s=" " +s+" ";
			}
			String wkey=leftStr(SqlNodeVar.getWhereStr(), SqlNodeVar.getWhereStr().length()-1);
			int pos=s.indexOf(wkey);
			if(pos>=0){
				while(pos>=0){
					String key=getWhereKey(s,pos);
					String sub=s.substring(0, pos);
					sql=addSql(fromtab, sub, input, param, sql);
					sql=addSql(fromtab, key, input, param, sql);
					s=s.substring(pos+key.length(), s.length());
					pos=s.indexOf(wkey);
				}
				sql=addSql(fromtab, s, input, param, sql);

//						String[] wlist=s.split(SqlNodeVar.getWhereStr());
//						int wlen=wlist.length;
//						for(int w=0; w<wlen; w++){
//							sql=addSql(fromtab, wlist[w], input, param, sql);
//							if(w!=(wlen-1) || wlen==1){
//								sql=addSql(fromtab, SqlNodeVar.getWhereStr().trim(), input, param, sql);
//							}
//						}
			} else {
				sql=addSql(fromtab, s, input, param, sql);
			}

		}
	}

	public String toString(){
		StringBuilder s= new StringBuilder();
		s.append("sql:"+this.sql+"\n");
		String s1="";
		int len=this.param.size();
		for(int i=0; i<len; i++){
			VarList var=this.param.get(i);
			s1=s1+var.getText();
			int zlen=var.size();
			for(int z=0; z<zlen; z++){
				s.append(var.get(z).getVar()+" : "+var.getText().substring(var.get(z).getStart(),var.get(z).getEnd()+1)+"\n");
			}
		}
		s.append("express sql:"+s1);
		return s.toString();
	}

	public String getAutoCompletion() {
		return autoCompletion;
	}

	public FromList getFromtab() throws Exception {
		if(fromtab!=null) return fromtab;
		if(rule!=null && rule.getFrom()!=null) return new FromList(rule.getFrom(), null, session);
		if(rule==null && sql!=null) return new FromList(null, sql, session);
		return fromtab;
	}

	public JSONArray getAuths() {
		return auths;
	}

	public QueryhTw getHtw() {
		if(htw==null) return null;
		if(head!=null) htw.setGridHead(head);
		return htw;
	}

	public GridHead getHead() {
		return head;
	}

	public XmlSqlPaste getXmlSqlPaste() {
		return xmlSqlPaste;
	}

	public void setXmlSqlPaste(XmlSqlPaste xmlSqlPaste) {
		this.xmlSqlPaste = xmlSqlPaste;
	}

	public SqlRule getSqlrule() {
		return sqlrule;
	}

	public String getSqlType() {
		return sqlType;
	}

	public void setSqlType(String sqlType) {
		this.sqlType = sqlType;
	}

	public String getDBCN() {
		return DBCN;
	}

	public JSONObject getOther() {
		return other;
	}

	public JSONObject getFroms() {
		return froms;
	}
}
